package com.base;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javassist.Modifier;

import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;

import com.bean.ParkManager;
import com.bean.RulerInfo;
import com.bean.RulerMethod;
import com.bean.RulerRole;
import com.bean.Syslog;
import com.bean.SysUser;
import com.dao.SysUserDao;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.service.ParkOrderService;
import com.service.RightService;
import com.service.RulerService;
import com.service.SyslogService;
import com.util.GUtil;

public abstract class BaseAction extends ActionSupport {

	/** serialVersionUID*/
	private static final long serialVersionUID = 6835442148146866693L;

	protected static final Logger log = Logger.getLogger(BaseAction.class);

	protected RightService rightService = null;
	protected SyslogService syslogService = null;
	protected RulerService  rulerService = null;

	//分页使用
	protected PageBean page = new PageBean();;

	protected HttpServletRequest request;
	protected HttpServletResponse  response;
	protected ServletContext sc;
	
	protected String RedirectUrl ;//after login redirect to this url
	
	protected String querytype;//查询类型  null | json | text

	protected static Config config = new Config(); 
	protected String headerTitle = null;//页面标题
	protected String method = null;//action调用方法名称
	protected String msg="";//返回页面的消息内容
	protected String logmsg = "";//计入操作日志的消息内容
	protected Map<String, Object> session = null;//

	protected UserBean user;//登录用户信息，存入session，数据来源于sys_user(系统用户)/park_manager(停车场用户)/userinfo(司机用户)
	protected Object userinfo = null;//系统用户
	protected SysUser sysuser = null;//系统用户
	protected ParkManager parkuser = null;//停车场用户
	protected String loginAction = null;
	protected String ip="";
	protected Boolean IgnoreBrowser = null;

	protected String str = null;
	protected Integer  id;//公用，一般为修改删除提供支持
	protected String goBackUrl = null;
	protected String referer=null;
	protected String target = null;

	protected String sortOrder=null;
	protected String sortField=null;

	private List<RulerRole> rulerRoleList = null;
	private List<RulerInfo> rulerInfolist = null;
	private String rightWord = null;

	private RulerInfo rulerInfoOut; // for checkRight2
	private RulerMethod rulerMethodOut;// for checkRight2

	protected Syslog syslog = new Syslog();
	private Map<String, Integer> IgnoreActionMap = null;//

	protected String action = null;
	protected String title = null;
	private Boolean saveLog;
	
	protected String  device;
	protected String token;
	protected Long userId;

	// override functions for standard
	public abstract String handle() throws Exception;
	public abstract String query() throws Exception;
	public abstract String add() throws Exception;
	public abstract String update() throws Exception;
	public abstract String delete() throws Exception;
	public abstract String view() throws Exception;
	public abstract boolean validate(Object obj) throws Exception;
	
	public String reLogin() throws IOException{
		
		//get RedirectUrl from cookie
		if(RedirectUrl==null){
			Cookie cookie = GUtil.getCookieByName(request, "RedirectUrl");
			if(cookie!=null){
				RedirectUrl = cookie.getValue();
				session.put("RedirectUrl", RedirectUrl);
			}
		}
		
		
		String loginActionStr = (String) session.get("loginAction");
		if(loginActionStr!=null)
			loginAction = loginActionStr;
		
		if(loginAction==null){
			Cookie cookie = GUtil.getCookieByName(request, "loginAction");
			if(cookie!=null){
				loginAction = cookie.getValue();
				session.put("loginAction", loginAction);
			}
		}
		
		JSONObject json = new JSONObject();
		if(querytype==null)
			return GUtil.LOGIN;
		else{
			if(querytype.equals("json")){
				json.put("error", -100);
				json.put("msg", "请先登录");
				json.put("url", "LoginAction");
				PrintWriter out = response.getWriter();
				out.print(json.toString());
				out.close();
				return GUtil.NONE;
			}
		}
		return GUtil.LOGIN;
	}

	@Override
	public String execute() throws Exception {

		request = ServletActionContext.getRequest();
		response = ServletActionContext.getResponse();
		sc = ServletActionContext.getServletContext();

		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");

		msg = "";
		request.setAttribute("faile", "");
		session = ActionContext.getContext().getSession();
		
		this.setReferer(request.getHeader("Referer"));

		ip = GUtil.parseIp(request, response);
		log.info("IP="+ip+" request url="+request.getRequestURL()+"?"+request.getQueryString()+", Referer=" + this.getReferer());

		//	method = request.getParameter("method"); //get with struts

		//获取访问的action名称
		Object actionClass = (Object) ActionContext.getContext().get("action");
		if(actionClass!=null)
			action = actionClass.getClass().getSimpleName();

		log.info("action="+  action+"?method="+method+"&id="+id);

		//LoginAction 或其无需权限访问的Action，可以直接进行处理handle(),在web.xml中配置IgnoreAction
		IgnoreActionMap = (Map<String, Integer>) ServletActionContext.getServletContext().getAttribute("IgnoreActionMap");
		if(IgnoreActionMap!=null){
			if(IgnoreActionMap.get(action)!=null)
				return handle();
		}

		user = (UserBean) session.get("user");
		//用户session失效，需要重新登录
		if(user==null){
			if( RedirectUrl!=null && !RedirectUrl.trim().isEmpty() )
				session.put("RedirectUrl", RedirectUrl);
			else if( action!=null  && action.endsWith("StatisticIndexAction") )
				session.put("RedirectUrl", RedirectUrl);
			//action = "IndexAction";
			return this.reLogin();
		}
		referer  = request.getHeader("referer");
		if(referer!=null)
			this.setGoBackUrl(referer);
		else
			this.setGoBackUrl(action);//设置页面返回按钮地址
		syslog.setUser(user);

		//检查权限
		//------- 下面的代码是检测用户是否拥有该操作权限和输出该action的操作权限methods到request----------
		rulerInfolist = (List<RulerInfo>) session.get("rulerInfolist");//获取拥有的菜单列表
		//	rulerRoleList = (List<RulerRole>) session.get("rulerRoleList");//获取拥有的权限列表

		//检查权限和输出操作权限method
		String checkRet = this.checkRequestRights(action, method);// retrun  rulerInfoOut, rulerMethodOut 
		if(checkRet==GUtil.FAILE)
		{
			msg = "警告：非法操作，请重新登录系统或联系管理员";
			syslog.setContent(action+"?method="+method+","+msg);
			syslogService.log(syslog);
			log.warn(msg);
			return this.reLogin();
		}else if(checkRet==GUtil.NULL){
			log.warn("checkRet==Util.NULL @ "+action+"?method="+method);
			return handle();
		}

		//应先检查权限,如果拥有该action,但是method==null,则调用该action的handle()进行默认处理
		if(method==null){
			Long t1 = System.currentTimeMillis();
			String handleReturn = handle();//maybe response.write the information
			Long t2 = System.currentTimeMillis();
			log.info("call the default method "+action+".handle() "+ " [takes "+ (t2-t1) + " ms] return "+handleReturn+" msg="+msg) ;
			return handleReturn;
		}

		//here it means  GUtil.SUCCESS
		//if method==null then rulerMethodOut==null
		if(rulerInfoOut==null){
			msg = "系统内部错误";
			log.error( BaseAction.class + ".  this is not should be happen, please check the logs carefully.");
			return GUtil.ERROR;
		}
		if(rulerMethodOut==null)
			rulerMethodOut = new RulerMethod();
		String rulermsg = "{RulerInfo:{id:"+rulerInfoOut.getRulerid()+",action:'"+rulerInfoOut.getUrl()+"',rulerName:'"+rulerInfoOut.getRulerName()+"'}," +
				"RulerMethod:{id:"+rulerMethodOut.getId()+",method:'"+rulerMethodOut.getMethod()+"',name:'"+rulerMethodOut.getName()+"'}}";

		//reflect 调用Action中的方法
		Method function = null;
		try{
			function = this.getClass().getDeclaredMethod(method);
		}catch(Exception e){
			function = null;
		}

		if(function==null){
			this.setMsg("请求的方法不存在");
			syslog.setContent( rulermsg + this.getLogmsg()+":"+this.getMsg());
			log.warn(syslog.getContent());
			syslogService.log(syslog);
			return GUtil.ERROR;
		}

		if(function.getModifiers() == Modifier.PUBLIC || function.getModifiers() == Modifier.PROTECTED){
			log.info( action+"."+function.getName()+".invoke("+this+")");
			Object returnObject = null;
			if(function.getReturnType()==String.class){
				Long t1 = System.currentTimeMillis();
				returnObject = function.invoke(this);//call the method
				Long t2 = System.currentTimeMillis();
				this.logmsg += " [takes "+ (t2-t1) + " ms]";
			}else{
				Long t1 = System.currentTimeMillis();
				function.invoke(this.getClass());//maybe response.write the information
				Long t2 = System.currentTimeMillis();
				this.logmsg += " [takes "+ (t2-t1) + " ms]";
				return GUtil.NONE;
			}
			syslog.setContent( rulermsg + this.getLogmsg()+":"+this.getMsg());
			log.info(syslog.getContent());

			if(saveLog!=null && saveLog!=false){
				//to do nothing 
			}else{
				if(!(rulerInfoOut.getUrl().startsWith("SyslogAction") || rulerInfoOut.getUrl().startsWith("SyslogAction")) )
					syslogService.log(syslog);
			}
			if(returnObject==null){
				log.info("BaseAction.execute() returnObject==null");
				return GUtil.NONE;
			}
			if(returnObject instanceof String)
				return (String)returnObject;
		}

		log.info("The end of BaseAction.execute(). This is not should be happen, please check your code.");
		return GUtil.NONE;
		//the end of BaseAction.execute()
	}

	/**
	 * 权限校验
	 * <p>Title: checkRights2</p>
	 * <p>Description:
	 * 		根据请求的action和method校验权限
	 *  </p>
	 * @param actionName
	 * @param methodName
	 * @param rulerInfoOut  成功后返回此项菜单的RulerInfo
	 * @param rulerMethodOut 成功后返回此项菜单method的RulerInfo的RulerMethod
	 * @return
	 * 		GUtil.SUCCESS | GUtil.FAILE
	 * 		rulerInfoOut
	 * 		rulerMethodOut
	 */
	String checkRequestRights(String actionName, String methodName){

		//Map<action, RulerInfo >
		Map<String, RulerInfo > rulermap =  (Map<String, RulerInfo>) session.get("rulermap"); 

		if(rulermap==null || rulermap.size()<1){
			return GUtil.FAILE;
		}
		RulerInfo rulerInfoTemp = rulermap.get(actionName);
		if(rulerInfoTemp==null){ // 根据action获取RulerInfo==null, 自己的菜单rulerInfo列表中不存在该菜单, 请求失败
			return GUtil.FAILE;
		}

		//Map<method, RulerMethod>
		Map<String, RulerMethod>  methodmap = rulerInfoTemp.getMethodmap();//获取权限method列表methodmap
		if(methodmap!=null || methodmap.size()>0)
		{
			//注意：此处一样要在交给handle()处理之前执行，否则在jsp页面获取的#reques.{method}都是空的
			//设置此action的methods,放入request, 此处应该检查method权限之前执行，因为method==null,会直接调用handle(),需要将methods放入request
			Iterator it = methodmap.keySet().iterator();
			while(it.hasNext()){
				String methodNameTemp = (String) it.next();
				//	RulerMethod rm =  methodmap.get(methodNameTemp);
				request.setAttribute(methodNameTemp.trim() , 1);//保存权限method到request, jsp中判断method大于0 即拥有该权限
		//		log.info("checkRights2 request.setAttribute("+methodNameTemp.trim()+" , 1)");
			}
		}else{
			return GUtil.FAILE;//虽然rulerInfoTemp存在，但是该rulerInfo没有任何method可以操作
		}
		rulerInfoOut = rulerInfoTemp;//set return RulerInfo;
		//该菜单存在，但请求的method==null,交给 xxxAction.handle()处理
		if(methodName==null || methodName.trim().isEmpty()){
			return GUtil.SUCCESS;
		}
		rulerMethodOut = methodmap.get(methodName.trim());//if methodName==null then rulerMethodOut==null

		RulerMethod rulerMethodTemp = rulerMethodOut ;
		//检测method!=null时的权限method
		if(rulerMethodTemp!=null){
			return GUtil.SUCCESS;
		}
		return GUtil.FAILE;
	}

	@Deprecated
	String getRightWord(String actionName){
		//根据actionName获取actionID
		int actionID = 0;
		for(int i=0; i<rulerInfolist.size(); i++){
			if(rulerInfolist.get(i).getUrl().startsWith(actionName) || rulerInfolist.get(i).getUrl().startsWith("/"+actionName)){
				actionID = rulerInfolist.get(i).getRulerid();
				break;
			}
		}
		if(actionID <1 )
			return null;

		//根据actionID获取rightWord
		String rightWord = null;
		for(int i=0; i<rulerRoleList.size(); i++){
			if(rulerRoleList.get(i).getRulerId() == actionID){
				rightWord = rulerRoleList.get(i).getRulerWord();
				break;
			}
		}
		return rightWord;
	}
	//通过页面id获取当前用户对当前页面的权限
	@Deprecated

	String checkRights(String actionName, String methodName)
	{
		if(rulerRoleList==null || rulerInfolist==null){
			return GUtil.FAILE;
		}
		rightWord = getRightWord(actionName);
		if(rightWord==null){
			//权限中不存在此action
			try {
				//如果数据库中存在此Action，则用户没有该权限，否则表面有该权限，
				//如LoginAction存在但没有在数据库中，任何用户用户该权限
				if(rightService.checkAction(actionName, methodName, user.getRole())==GUtil.SUCCESS)
					return GUtil.FAILE;
				else
					return GUtil.SUCCESS;
			} catch (Exception e) {
				e.printStackTrace();
			}
			return GUtil.FAILE;
		}else if(rightWord.trim().isEmpty()){
			// read only
			return GUtil.SUCCESS;
		}else{
			rightWord = rightWord.toLowerCase();
			String rightkeys [] = rightWord.split("");
			for(String key : rightkeys){
				request.setAttribute(key, 1);//保存权限->jsp, 大于0 即拥有该权限
			}
			if(methodName==null)
				return GUtil.SUCCESS;

			char ch = ' ';
			if(methodName.endsWith("beforeAdd") || methodName.endsWith("add"))
				ch = 'i';
			else if(methodName.endsWith("beforeUpdate") || methodName.endsWith("update") )
				ch = 'u';
			else  if(methodName.endsWith("delete") )
				ch = 'd';
			else  if(methodName.endsWith("view") )
				ch = 'v';
			if(ch!=' '){
				if(rightWord.indexOf(ch)>=0)
					return GUtil.SUCCESS;
				else
					return GUtil.FAILE;
			}else
				return GUtil.SUCCESS;
		}

		/*
		//点击菜单默认执行查询操作
		if(methodName==null || methodName.endsWith("query")){ // 菜单权限
			for(int i=0; i<rulerInfolist.size(); i++){
				//判断权限是否运行执行(存在)此action
				if(rulerInfolist.get(i).getUrl().startsWith(actionName) || rulerInfolist.get(i).getUrl().startsWith("/"+actionName)){
					request.setAttribute("u", rightWord.indexOf("u"));
					request.setAttribute("v", rightWord.indexOf("v"));
					request.setAttribute("i", rightWord.indexOf("i"));
					request.setAttribute("d", rightWord.indexOf("d"));

					return Util.SUCCESS;
				}
			}

			return Util.FAILE;
		}
		else{
			//对于非query操作(update/delete/add)进行检查是否音乐次全新
			char ch = 'v';
			if(methodName.endsWith("beforeAdd") || methodName.endsWith("add"))
				ch = 'i';
			else if(methodName.endsWith("beforeUpdate") || methodName.endsWith("update") )
				ch = 'u';
			else  if(methodName.endsWith("delete") )
				ch = 'd';
			else  if(methodName.endsWith("view") )
				ch = 'v';

			if(rightWord.indexOf(ch)>=0)
				return Util.SUCCESS;
			else
				return Util.FAILE;
		}
		 */
	}

	
	public void addCookie(String name, String value){
		Cookie cookie = new Cookie(name, value);
		cookie.setMaxAge(3600*24*7);
		cookie.setPath("/");//设置路径，这个路径即该工程下都可以访问该cookie 如果不设置路径，那么只有设置该cookie路径及其子路径可以访问
		response.addCookie(cookie);
	}

	// getter & setter

	public RightService getRightService() {
		return rightService;
	}

	public void setRightService(RightService rightService) {
		this.rightService = rightService;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public String getMethod() {
		return method;
	}

	public void setMethod(String method) {
		if(method.endsWith("?"))
			method = method.substring(0, method.length()-2);
		this.method = method;
	}

	public String getGoBackUrl() {
		return goBackUrl;
	}
	public void setGoBackUrl(String url) {
		if(url==null || url.isEmpty())
			goBackUrl = "javascript:history.go(-1)";
		else
			this.goBackUrl = url;
		log.info("goBackUrl="+goBackUrl);
	}
	public String getSortOrder() {
		return sortOrder;
	}
	public void setSortOrder(String sortOrder) {
		this.sortOrder = sortOrder;
	}
	public String getSortField() {
		return sortField;
	}
	public void setSortField(String sortField) {
		this.sortField = sortField;
	}
	public String getAction() {
		return action;
	}
	public void setAction(String action) {
		this.action = action;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getTarget() {
		return target;
	}
	public void setTarget(String target) {
		this.target = target;
	}
	public SyslogService getSyslogService() {
		return syslogService;
	}
	public void setSyslogService(SyslogService syslogService) {
		this.syslogService = syslogService;
	}
	public RulerService getRulerService() {
		return rulerService;
	}
	public void setRulerService(RulerService rulerService) {
		this.rulerService = rulerService;
	}
	public String getLogmsg() {
		return logmsg;
	}
	public void addLogmsg(String logmsg) {
		this.logmsg += logmsg;
	}
	public void setLogmsg(String logmsg) {
		this.logmsg = logmsg;
	}
	/**
	 * @return the page
	 */
	public PageBean getPage() {
		return page;
	}
	/**
	 * @param page the page to set
	 */
	public void setPage(PageBean page) {
		this.page = page;
	}
	/**
	 * @return the title
	 */
	public String getTitle() {
		return title;
	}
	/**
	 * @param title the title to set
	 */
	public void setTitle(String title) {
		this.title = title;
		config.setTitle(title);
		sc.setAttribute("config", config);
	}
	/**
	 * @return the parkuser
	 */
	public ParkManager getParkuser() {
		return parkuser;
	}
	/**
	 * @param parkuser the parkuser to set
	 */
	public void setParkuser(ParkManager parkuser) {
		this.parkuser = parkuser;
	}
	/**
	 * @return
	 * @see java.lang.Boolean#booleanValue()
	 */
	public boolean booleanValue() {
		return saveLog.booleanValue();
	}
	/**
	 * @return the user
	 */
	public UserBean getUser() {
		return user;
	}
	/**
	 * @param user the user to set
	 */
	public void setUser(UserBean user) {
		this.user = user;
	}
	/**
	 * @return the loginAction
	 */
	public String getLoginAction() {
		return loginAction;
	}
	/**
	 * @param loginAction the loginAction to set
	 */
	public void setLoginAction(String loginAction) {
		this.loginAction = loginAction;
	}
	/**
	 * @return the headerTitle
	 */
	public String getHeaderTitle() {
		return headerTitle;
	}
	/**
	 * @param headerTitle the headerTitle to set
	 */
	public void setHeaderTitle(String headerTitle) {
		this.headerTitle = headerTitle;
	}
	/**
	 * @return the referer
	 */
	public String getReferer() {
		return referer;
	}
	/**
	 * @param referer the referer to set
	 */
	public void setReferer(String referer) {
		this.referer = referer;
	}
	public ParkOrderService getParkOrderService() {
		// TODO Auto-generated method stub
		return null;
	}
	/**
	 * @return the id
	 */
	public Integer getId() {
		return id;
	}
	/**
	 * @return the querytype
	 */
	public String getQuerytype() {
		return querytype;
	}
	/**
	 * @param querytype the querytype to set
	 */
	public void setQuerytype(String querytype) {
		this.querytype = querytype;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	public String getDevice() {
		return device;
	}
	public void setDevice(String device) {
		this.device = device;
	}
	public String getToken() {
		return token;
	}
	public void setToken(String token) {
		this.token = token;
	}
	public Long getUserId() {
		return userId;
	}
	public void setUserId(Long userId) {
		this.userId = userId;
	}
	public Boolean getIgnoreBrowser() {
		return IgnoreBrowser;
	}
	public void setIgnoreBrowser(Boolean ignoreBrowser) {
		IgnoreBrowser = ignoreBrowser;
	}
	public String getRedirectUrl() {
		return RedirectUrl;
	}
	public void setRedirectUrl(String redirectUrl) {
		RedirectUrl = redirectUrl;
	}


}